]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
extensionSystem: Update immediately after major upgrades
authorFlorian Müllner <fmuellner@gnome.org>
Thu, 14 Sep 2023 18:30:39 +0000 (20:30 +0200)
committerMarge Bot <marge-bot@gnome.org>
Fri, 15 Sep 2023 12:54:41 +0000 (12:54 +0000)
Currently we periodically check for updated extensions, prepare
an update and perform it at the next login.

This is largely due to the fact that once an extension has been
loaded, its code is cached and reloading it would only make it
*appear* as updated, while in reality still running the old code.

Of course this only applies *once* we have loaded extensions.

Before that, it's possible to download and install updates, and
only then initialize extensions with their latest version.

The trade-off is that network requests, data download and extraction may
introduce a significant delay before extensions
are enabled. Most extensions modify the UI one way or another,
so that delay would likely be noticeable by the user.

Assuming that users are usually happy enough with the current
extension version, that trade-off doesn't seem worthwhile.

However there is an exception: After a major version update,
extensions are likely disabled as out-of-date, or at least
more likely to break (when the version check is disabled).

In that case delaying extension initialization to download
and install updates looks like the better trade-off, so do
that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2951>

js/ui/extensionSystem.js

index 21b3b196f7037df937bc495eaed07b50d4e1acad..3592e5b3a957dcda2a1b7d28707d25c16605ce79 100644 (file)
@@ -27,6 +27,8 @@ export class ExtensionManager extends Signals.EventEmitter {
 
         this._initializationPromise = null;
         this._updateNotified = false;
+        this._updateInProgress = false;
+        this._updatedUUIDS = [];
 
         this._extensions = new Map();
         this._unloadedExtensions = new Map();
@@ -316,6 +318,11 @@ export class ExtensionManager extends Signals.EventEmitter {
     }
 
     notifyExtensionUpdate(uuid) {
+        if (this._updateInProgress) {
+            this._updatedUUIDS.push(uuid);
+            return;
+        }
+
         let extension = this.lookup(uuid);
         if (!extension)
             return;
@@ -646,6 +653,30 @@ export class ExtensionManager extends Signals.EventEmitter {
         }
     }
 
+    async _handleMajorUpdate() {
+        const [majorVersion] = Config.PACKAGE_VERSION.split('.');
+        const path = `${global.userdatadir}/update-check-${majorVersion}`;
+        const file = Gio.File.new_for_path(path);
+
+        try {
+            if (!await file.touch_async())
+                return;
+        } catch (e) {
+            logError(e);
+        }
+
+        this._updateInProgress = true;
+
+        await ExtensionDownloader.checkForUpdates();
+        this._installExtensionUpdates();
+
+        this._updatedUUIDS.map(uuid => this.lookup(uuid)).forEach(
+            ext => this.reloadExtension(ext));
+        this._updatedUUIDS = [];
+
+        this._updateInProgress = false;
+    }
+
     _installExtensionUpdates() {
         if (!this.updatesSupported)
             return;
@@ -719,6 +750,10 @@ export class ExtensionManager extends Signals.EventEmitter {
             return extension;
         }).filter(extension => extension !== null);
 
+        // after updating to a new major version,
+        // update extensions before loading them
+        await this._handleMajorUpdate();
+
         for (const extension of extensionObjects) {
             // eslint-disable-next-line no-await-in-loop
             await this.loadExtension(extension);